import React, {
	ChangeEvent,
	KeyboardEvent,
	useEffect,
	useRef,
	useState
} from 'react'
import Input from '../Input/input'
import Icon from '../Icon/icon'
import useDebounce from '../../hooks/useDebounce'
import { type AutoCompleteProps, type DataSourceType } from './types'
import classNames from 'classnames'
import useClickOutside from '../../hooks/useClickOutside'
import Transition from '../Transition/transition'

const AutoComplete: React.FC<AutoCompleteProps> = ({
	fetchSuggestions,
	onSelect,
	value,
	renderOption,
	...restProps
}) => {
	const [inputValue, setInputValue] = useState(value as string)
	const [suggestions, setSuggestions] = useState<DataSourceType[]>([])
	const [loading, setLoading] = useState(false)
	const [showDropdown, setShowDropdown] = useState(false)
	const debouncedValue = useDebounce(inputValue)
	const [highlightIndex, setHighlightIndex] = useState(-1)
	const triggerSearch = useRef(false)
	const componentRef = useRef<HTMLDivElement>(null)
	useClickOutside(componentRef, () => {
		setSuggestions([])
	})
	useEffect(() => {
		if (debouncedValue && triggerSearch.current) {
			const results = fetchSuggestions(debouncedValue)
			if (results instanceof Promise) {
				setLoading(true)
				results.then((data) => {
					setSuggestions(data)
					setLoading(false)
					if (data.length) {
						setShowDropdown(true)
					}
				})
			} else {
				setSuggestions(results)
				setShowDropdown(true)
				if (results.length) {
					setShowDropdown(true)
				}
			}
		} else {
			// setSuggestions([])
			setShowDropdown(false)
		}

		setHighlightIndex(-1)
	}, [debouncedValue, fetchSuggestions])

	const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
		const value = e.target.value.trim()
		setInputValue(value)
		triggerSearch.current = true
		/* if (value) {
			const results = fetchSuggestions(value)
			if (results instanceof Promise) {
				setLoading(true)
				results.then((data) => {
					setSuggestions(data)
					setLoading(false)
				})
			} else {
				setSuggestions(results)
			}
		} else {
			setSuggestions([])
		} */
	}
	const handleSelect = (item: DataSourceType) => {
		setInputValue(item.value)
		// setSuggestions([])
		setShowDropdown(false)
		if (onSelect) {
			onSelect(item)
		}
		triggerSearch.current = false
	}
	const highlight = (index: number) => {
		if (index < 0) {
			index = 0
		}
		if (index >= suggestions.length) {
			index = suggestions.length - 1
		}
		setHighlightIndex(index)
	}
	const handleKeydown = (e: KeyboardEvent<HTMLInputElement>) => {
		switch (e.keyCode) {
			case 13: // enter
				suggestions[highlightIndex] && handleSelect(suggestions[highlightIndex])
				break
			case 38: // 向上
				highlight(highlightIndex - 1)
				break
			case 40: // 向下
				highlight(highlightIndex + 1)
				break
			case 27: // esc
				// setSuggestions([])
				setShowDropdown(false)
				break
			default:
				break
		}
	}

	const renderTemplate = (item: DataSourceType) => {
		return renderOption ? renderOption(item) : item.value
	}
	const genDropdown = () => {
		return (
			<Transition
				in={showDropdown || loading}
				animation="zoom-in-top"
				timeout={300}
				onExited={() => setSuggestions([])}
			>
				<ul className="v-suggestion-list">
					{loading && (
						<div className="suggestions-loading-icon">
							<Icon icon="spinner" spin />
						</div>
					)}
					{suggestions.map((suggestion, index) => {
						const classes = classNames('suggestion-item', {
							'item-highlighted': index === highlightIndex
						})
						return (
							<li
								key={index}
								onClick={() => handleSelect(suggestion)}
								className={classes}
							>
								{renderTemplate(suggestion)}
							</li>
						)
					})}
				</ul>
			</Transition>
		)
	}

	return (
		<div className="v-auto-complete" ref={componentRef}>
			<Input
				value={inputValue}
				onChange={handleChange}
				onKeyDown={handleKeydown}
				{...restProps}
			></Input>
			{genDropdown()}
		</div>
	)
}

export default AutoComplete
